/* 
Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/** @fileoverview
 * Interface with FAE 
 */
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {
	var AE = AccessibilityExtension.ns;  
	var accessext_mergedDocsIframes = [];
AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{	
	ParseDocumentADDDimensionInfo: function(aeModifiedNodes) {
		try {
		   	var documents = accessext_getDocumentList(content.document);
			for (var i=0; i < documents.length; i++)  { //frames
				for(var j = 0; j < documents[i].images.length; j++) {
					//loadArray[loadArray.length] = new imagesObject(loadArray.length + 1,doc.images[i]);
					//var width = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("width");
					//var height = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("height");
					var width = documents[i].defaultView.getComputedStyle(documents[i].images[j], null).getPropertyValue("width");
					var height = documents[i].defaultView.getComputedStyle(documents[i].images[j], null).getPropertyValue("height");
					documents[i].images[j].setAttribute('ae_width', width);
					documents[i].images[j].setAttribute('ae_height', height);
					aeModifiedNodes.push(documents[i].images[j]);
				}
			}
			return aeModifiedNodes;
		} catch (ex) {
			accessext_consoleDump('ParseDocumentADDColourInfo exception: ', ex);
		}
	
	},
	toHex: function(colour) {
	        var r = colour.red.toString(16);
	        var g = colour.green.toString(16);
	        var b = colour.blue.toString(16);
	        if (r.length == 1) r = '0' + r;
	        if (g.length == 1) g = '0' + g;
	        if (b.length == 1) b = '0' + b;
	        return '#' + r + g + b;
	},
	
	ParseDocumentADDColourInfo: function() { 
		try {
			var aeModifiedNodes = new Array();
			var iCounter = 0;
			var baseuri = "";
			var objOriginalBody = content.document.getElementsByTagName('body')[0];
			
			if (objOriginalBody) {
				baseuri = getBaseURI(objOriginalBody);
				arElements = examineContrast(2, objOriginalBody);			
				for (; iCounter<arElements.length; iCounter++)
				{
					//this enable us to pass the color information to FAE
					arElements[iCounter].node.setAttribute('ae_color', toHex(objElementDetails.forecolour));
					arElements[iCounter].node.setAttribute('ae_background-color', toHex(objElementDetails.backcolour));
					arElements[iCounter].node.setAttribute('ae_luminosity', objElementDetails.luminosity[0]);
					aeModifiedNodes.push(arElements[iCounter].node);
				}
			} else {
		   		var documents = accessext_getDocumentList(content.document);
				for (var i=0; i < documents.length; i++)  { //frames
					objOriginalBody = documents[i].getElementsByTagName('body')[0];	
					if (objOriginalBody) { 
						baseuri = getBaseURI(objOriginalBody);
						arElements = examineContrast(2, objOriginalBody);
						for (; iCounter<arElements.length; iCounter++)
						{
							//this enable us to pass the color information to FAE
							arElements[iCounter].node.setAttribute('ae_color', toHex(objElementDetails.forecolour));
							arElements[iCounter].node.setAttribute('ae_background-color', toHex(objElementDetails.backcolour));
							arElements[iCounter].node.setAttribute('ae_luminosity', objElementDetails.luminosity[0]);
							aeModifiedNodes.push(arElements[iCounter].node);
						}
					}
				}			
			}
			return aeModifiedNodes;
		} catch (ex) {
			accessext_consoleDump('ParseDocumentADDColourInfo exception: ', ex);
		}
	},
	
	removeAEAddedAttributes: function(aeModifiedNodes) {
		try {
			if (aeModifiedNodes) {
				for (var i=0; i < aeModifiedNodes.length; i++)  { //frames
					if (aeModifiedNodes[i].hasAttribute('ae_color')) aeModifiedNodes[i].removeAttribute('ae_color'); 
					if (aeModifiedNodes[i].hasAttribute('ae_background-color')) aeModifiedNodes[i].removeAttribute('ae_background-color'); 
					if (aeModifiedNodes[i].hasAttribute('ae_luminosity')) aeModifiedNodes[i].removeAttribute('ae_luminosity'); 
					if (aeModifiedNodes[i].hasAttribute('ae_width')) aeModifiedNodes[i].removeAttribute('ae_width'); 
					if (aeModifiedNodes[i].hasAttribute('ae_height')) aeModifiedNodes[i].removeAttribute('ae_height'); 
				}
			}
		} catch (ex) {
			accessext_consoleDump('removeAEAddedAttributes exception: ', ex);
		}
	
	},
	
	/** Serializes the DOM and sends to FAE
	 * @returns None
	 */
	accessext_invokeFAE: function(debug) {
		try {
		//   var aeModifiedNodes = ParseDocumentADDColourInfo(); //color information added to the node
		//   aeModifiedNodes = ParseDocumentADDDimensionInfo(aeModifiedNodes);
		   
		   var serializedDocs = [];   
		   var documentList = accessext_getDocumentList(content.document);
		   
		   var pref = getAccessextPrefService();
		   
		   var merged = pref.getBoolPref("fae.mergeFrames");
		   var includeIframes = pref.getBoolPref("fae.includeIframes");
		   if(documentList.length > 1) { // then there must be some frames somewhere     
		      switch(merged) {
		         case true:
		            var mergedDocs = accessext_mergeFramedDocs_wrapper(documentList, merged);
		            serializedDocs[0] = accessext_serializeDOM(mergedDocs);           
		            if(includeIframes) {
		               serializedDocs = accessext_mergeIframes(accessext_mergedDocsIframes, serializedDocs, merged);
		               accessext_mergedDocsIframes = [];
		            }
		            break;
		         case false:
		            var frameDocs = accessext_getFrames(documentList, merged);
		            serializedDocs = frameDocs.map(accessext_serializeDOM);
		            if(includeIframes) {
		               serializedDocs = accessext_mergeIframes(frameDocs, serializedDocs, merged);
		            }
		            break;
		      }
		   } else { // there is only one document, just serialize it and send it
		         serializedDocs[0] = accessext_serializeDOM(documentList[0]);
		         if(includeIframes) {
		            serializedDocs = accessext_mergeIframes(documentList, serializedDocs, false);
		         }
		   }     
		   accessext_initFAEPreferences(documentList[0]);  
		   if(!debug){
		      accessext_createPostPage(serializedDocs);
		   } else {
		      for(var i = 0; i < serializedDocs.length; i++) {
		      //   alert(serializedDocs[i]);
				 displayInTextarea(serializedDocs[i]);     
		      }
		   }
		//   removeAEAddedAttributes(aeModifiedNodes); // added via ParseDocumentADDColourInfo
		   
		} catch (ex) {
			accessext_consoleDump('ParseDocumentForColourContrast exception: ', ex);
		}
	},
	
	accessext_docProperties: function(doctype, lang, content, title, body) {
	   this.doctype = doctype;
	   this.lang = lang;
	   this.content = content;
	   this.title = title;
	   this.body = body;
	},
	
	accessext_getDocumentList: function(initialDocument) {
	   var framesList = initialDocument.defaultView.frames;
	   var returnDocumentList = new Array();
	   returnDocumentList.push(initialDocument);
	
	   for(var flIndex = 0; flIndex < framesList.length; flIndex++) {
	      returnDocumentList.push(framesList[flIndex].document);
	   }  
	   return returnDocumentList;
	},
	
	accessext_mergeFramedDocs_wrapper: function(documentList, merged) {
	   var mergedFrames = null;   
	   var parentDoc = documentList[0];
	   var bodyNodeName = parentDoc.body.nodeName.toLowerCase();
	   
	   if(bodyNodeName === "frameset") {
	      var visibleFrameDocs = accessext_getVisibleFrames(documentList, merged);
	      visibleFrameDocs.shift();
	      
	      var frameDocs = [];
	      for(var frame = 0; frame < visibleFrameDocs.length; frame++) {
	         var subFrameDocs = accessext_getDocumentList(visibleFrameDocs[frame]);
	         frameDocs.push(accessext_mergeFramedDocs_wrapper(subFrameDocs, merged));
	      }
	      
	      var parentDocProps = accessext_setProps(parentDoc);
	      var frameDocsProps = accessext_setFrameDocsProps(frameDocs);
	      
	      mergedFrames = accessext_mergeFramedDocs(parentDocProps, frameDocsProps);
	   } else if(bodyNodeName === "body") {
	      // check if iframes need to be merged
	      accessext_mergedDocsIframes.push(parentDoc);
	      mergedFrames = parentDoc;
	   }
	   
	   return mergedFrames;
	},
	
	accessext_getVisibleFrames: function(documentList, merged) {
	   var visibleFrameDocs = accessext_getFrames(documentList, merged);
	   
	   return visibleFrameDocs;
	},
	
	accessext_setProps: function(doc) {
	   var docProps = new accessext_docProperties(null, null, null, null, null);
	   
	   var metaElements = doc.getElementsByTagName("meta");
	   for(var metaIndex = 0; metaIndex < metaElements.length; metaIndex++) {
	      var httpequiv = metaElements[metaIndex].getAttribute("http-equiv");
	      var content = metaElements[metaIndex].getAttribute("content");
	      var httpequivRegex = new RegExp("Content-Type");
	      var contentRegex = new RegExp("text/html; charset=.*");
	      
	      if(httpequivRegex.test(httpequiv) && contentRegex.test(content)) {
	         docProps.content = metaElements[metaIndex].cloneNode(false);
	      }     
	   }
	   if(doc.doctype != null) {
	      docProps.doctype = doc.doctype.cloneNode(true);
	   }
	   if(doc.documentElement.hasAttribute("lang") || doc.documentElement.hasAttribute("xml:lang")) {
	      docProps.lang = doc.documentElement.cloneNode(false);
	   }  
	   if(doc.getElementsByTagName("title")[0] != null) {
	      docProps.title = doc.getElementsByTagName("title")[0].cloneNode(true);
	   }
	   
	   docProps.body = doc.body.cloneNode(true);
	   return docProps;
	},
	
	accessext_setFrameDocsProps: function(frameDocs) {
	   var frameDocsProps = [];
	   
	   for(var frame = 0; frame < frameDocs.length; frame++) {
	      var docProps = accessext_setProps(frameDocs[frame]);
	      frameDocsProps.push(docProps);
	   }
	   
	   return frameDocsProps;
	},
	
	accessext_mergeFramedDocs: function(parentDocProps, frameDocsProps) {
	   var mergedFrameSizes = accessext_getMergedFrameSizes(parentDocProps.body);
	
	   if(mergedFrameSizes.length != frameDocsProps.length) {
	      accessext_consoleDump("ERROR - number of nonzero rows/cols (" + mergedFrameSizes.length + ") and visible frames (" + frameDocsProps.length + ") are different");
	   } else {
	      var largestFrameIndex = 0;
	      for(var i = 0; i < mergedFrameSizes.length; i++) {
	         if(mergedFrameSizes[i] > mergedFrameSizes[largestFrameIndex]) {
	            largestFrameIndex = i;
	         }
	      }  
	      
	      var mergedDocImplementation = content.document.implementation;
	      var mergedDoc;
	      
	      // get the largest frame
	      var largestFrame = frameDocsProps[largestFrameIndex];
	   
	      if(useProperty(parentDocProps, frameDocsProps, "doctype")) {
	         var doctype = mergedDocImplementation.createDocumentType(largestFrame.doctype.name, 
	            largestFrame.doctype.publicId, largestFrame.doctype.systemId);
	         mergedDoc = mergedDocImplementation.createDocument(null, "HTML", doctype);
	      } else {
	         mergedDoc = foo.createDocument(null, "HTML", null);
	      }
	      if(useProperty(parentDocProps, frameDocsProps, "lang")) {
	         mergedDoc.replaceChild(largestFrame.lang, mergedDoc.documentElement);
	      }
	      
	      // add a header to the document
	      mergedDoc.documentElement.appendChild(mergedDoc.createElement("HEAD"));
	      if(useProperty(parentDocProps, frameDocsProps, "content")) {
	         mergedDoc.getElementsByTagName("HEAD")[0].appendChild(largestFrame.content);
	      }
	      if(useProperty(parentDocProps, frameDocsProps, "title")) {
	         mergedDoc.getElementsByTagName("HEAD")[0].appendChild(parentDocProps.title);
	      }
	      
	      mergedDoc.documentElement.appendChild(mergeBodies(frameDocsProps));
	      mergedDoc.body = mergeBodies(frameDocsProps);
	      
	      return mergedDoc;
	
	   }
	   
	   function useProperty(parentDocProps, frameDocsProps, prop) {
	      var useProp = true;
	      if(parentDocProps[prop] == null) {
	         useProp = false;
	      //} else if(prop != "title"){
	      } else{
	         for(var i = 0; i < frameDocsProps.length; i++) {
	            if(frameDocsProps[i][prop] == null) {
	               useProp = false;
	            }
	         }
	      }
	            
	      return useProp;
	   }
	   
	   function mergeBodies(frameDocsProps) {
	      var bodyNode = content.document.createElement("body");
	      for(var i = 0; i < frameDocsProps.length; i++) {
	         bodyNode.innerHTML = bodyNode.innerHTML + frameDocsProps[i].body.innerHTML;
	      }
	      return bodyNode;
	   }
	},
	
	accessext_getMergedFrameSizes: function(framesetNode) {
	   var framedSizes = accessext_getAllFrameSizes(framesetNode);
	   
	   function greaterThanZero(element, index, array) {
	     return (element > 0);
	   }  
	   return framedSizes.filter(greaterThanZero);
	},
	
	accessext_getFrames: function(documentList, merged) {
	   var topDoc = documentList.shift();
	   var returnDocs = new Array(topDoc);
	
	   switch(topDoc.body.tagName) {
	      case "FRAMESET":
	         var allFrameSizes = accessext_getAllFrameSizes(topDoc.body);
	
	         for(var i = 0; i < documentList.length; i++) {
	            if(allFrameSizes[i] > 0) {
	               if(merged){
	                  returnDocs.push(documentList[i]);
	               } else {
	                  var docsList = accessext_getDocumentList(documentList[i]);
	                  var newDocsList = accessext_getFrames(docsList, merged);
	                  returnDocs = returnDocs.concat(newDocsList);
	               }
	            }
	         }
	         break;
	      case "BODY":
	          break;
	   }  
	   return returnDocs;
	},
	
	accessext_mergeIframes: function(orgDocs, serDocs, merged) {
	   var serDocsIndex = 0;
	   for(var org = 0; org < orgDocs.length; org++) {
	      if(!merged) {
	         serDocsIndex = org;
	      }
	      if(orgDocs[org].body.tagName.toLowerCase() === "body") {
	         var iframeDocs = accessext_getDocumentList(orgDocs[org]);
	         var topDoc = iframeDocs.shift();
	         var iframes = topDoc.getElementsByTagName("IFRAME");
	         for(var ifm = 0; ifm < iframes.length; ifm++) {
	            if(accessext_isVisible(iframes[ifm])) {
	               var serNode = accessext_serializeDOM(iframes[ifm]);
	               var re = new RegExp(serNode, "ig");
	               var replace = "<div>" + iframeDocs[ifm].body.innerHTML + "</div>";
	               serDocs[serDocsIndex] = serDocs[serDocsIndex].replace(re, replace);
	            }
	         }
	      }
	   }
	   return serDocs;
	},
	
	accessext_isVisible: function(element) {
	   var display = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("display");
	   var position = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("position");
	   var width = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("width");
	   var height = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("height");
	   var leftPos = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("left");
	   var topPos = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("top");
	   var visibility = content.document.defaultView.getComputedStyle(element, null).getPropertyValue("visibility");
	   
	   width = parseInt(width.slice(0, width.length-2));
	   height = parseInt(height.slice(0, height.length-2));
	   leftPos = parseInt(leftPos.slice(0, leftPos.length-2));
	   topPos = parseInt(topPos.slice(0, topPos.length-2));
	      
	   if((display === "none") ||
	      ((position === "absolute") && ((topPos < (0 - height)) || (leftPos < (0 - width)))) ||
	      (visibility === "hidden")) {
	      return false;
	   } else {
	      return true;
	   }
	   
	},
	
	accessext_getAllFrameSizes: function(framesetNode) {
	   var returnFrameSizes = new Array();
	   var frameSizes = accessext_getFramesizes(framesetNode);
	
	   var tempChildren = framesetNode.childNodes;
	   var framesetChildren = new Array();
	   for(var i = 0; i < tempChildren.length; i++) {
	      var name = tempChildren[i].nodeName;
	      if((name == "FRAME") || (name == "FRAMESET")) {
	         framesetChildren.push(tempChildren[i]);
	      }
	   }
	   
	   if(framesetChildren.length <= frameSizes.length) { // SMF 8/28/07 just in case the author specifies for than they actually use
	      for(var i = 0; i < framesetChildren.length; i++) {
	         switch(framesetChildren[i].nodeName) {
	            case "FRAME":
	               returnFrameSizes.push(frameSizes[i]);
	               break;
	            case "FRAMESET":              
	               var tempFrameSizes = accessext_getAllFrameSizes(framesetChildren[i]);
	               if(frameSizes[i] > 0) {
	                  returnFrameSizes = returnFrameSizes.concat(tempFrameSizes);                
	               } else {
	                  for(var size = 0; size < tempFrameSizes.length; size++) {
	                     returnFrameSizes = returnFrameSizes.concat(0);  
	                  }
	               }
	               break;
	         }
	      }
	      return returnFrameSizes;
	   } else {
	      accessext_consoleDump("Malformed HTML - the number of rows or cols is different than the number of frames");
	      return null;
	   }
	   
	},
	
	accessext_getFramesizes: function(framesetNode) {
	   var rowsCols;  //array of the size, in pixels, of the rows or cols of the frameset
	   if(framesetNode.hasAttribute("rows")) {
	      rowsCols = accessext_getRowsCols(framesetNode, "rows");
	   } else if(framesetNode.hasAttribute("cols")) {
	      rowsCols = accessext_getRowsCols(framesetNode, "cols");
	   } else {
	      accessext_consoleDump("framesetNode has no rows/cols attr");
	   }  
	   return rowsCols;
	},
	
	accessext_getRowsCols: function(framesetNode, attribute) {
	   var rowsCols = framesetNode.getAttribute(attribute).split(/,\s*/);
	   return accessext_convertRowsColsToPixels(rowsCols, attribute);
	},
	
	accessext_convertRowsColsToPixels: function(rowsCols, attribute) {
	   var newRowsCols = new Array();
	   var docSize = 0;
	   if(attribute == "rows") {
	      docSize = document.defaultView.innerHeight;
	   } else {
	      docSize = document.defaultView.innerWidth;
	   }
	   
	   var starIndices = new Array();
	   var frameSizeWithoutStars = 0;
	   for(var i = 0; i < rowsCols.length; i++) {
	      var value = rowsCols[i].match(/%|px|\*/);
	      
	      if(!value) {   // if value is null, set it to "num";
	         value = ["num"];
	      }
	      
	      switch (value[0]) {
	         case "%":
	            var percentage = parseInt(rowsCols[i].slice(0, rowsCols[i].length), 10);
	            newRowsCols[i] = (docSize * percentage)/100;
	            frameSizeWithoutStars += newRowsCols[i];                 
	            break;
	         case "px":
	            newRowsCols[i] = parseInt(rowsCols[i].slice(0, rowsCols[i].length-1), 10);
	            frameSizeWithoutStars += newRowsCols[i];
	            break;
	         case "num":
	            newRowsCols[i] = parseInt(rowsCols[i].substring(0), 10);
	            frameSizeWithoutStars += newRowsCols[i];
	            break;
	         case "*":
	            starIndices.push(i);
	            break;
	         default:
	            alert("Frameset " + attribute + " formatted incorrectly");
	            break;
	      }
	   }
	   
	   var starSize = (docSize - frameSizeWithoutStars)/starIndices.length; // startIndices.length is the number of stars found
	   for(var starIndex = 0; starIndex < starIndices.length; starIndex++) {
	      var rowColIndex = starIndices[starIndex];
	      newRowsCols[rowColIndex] = starSize;
	   }
	   
	   return newRowsCols;
	},
	
	/** Returns the xml serialization ofa subtree.
	 * From: http://xulplane.com/tutorials/mozsdk/xmlparse.php
	 * @param node DOM node including and below which to serialize
	 * @returns A string with the XML serialization
	 * @type String
	 */
	accessext_serializeDOM: function(node) {
	   var serializer = new XMLSerializer();
	   return serializer.serializeToString(node);
	},
	
	/** Initializes preferences associated with FAE/Extension functionality if they do not already exist
	 * @returns None
	 */
	accessext_initFAEPreferences: function(currentDoc) {
	   var pref = getAccessextPrefService();
	   var prefix = "fae.";
	   var defaults = [
	   	// !!! search for fae.cita.uiuc.edu it needs to be changed in 2 places !!!
	    //  [prefix + "url", "http://faeserv.dres.uiuc.edu/evaluate/dhtml/"], // URL we post our data to
	      [prefix + "url", "https://fae.cita.illinois.edu/evaluate/dhtml/"], // URL we post our data to
	      [prefix + "docURL", currentDoc.URL],   //URL of the current document
	      [prefix + "mode.value", "ext"], // misc parameters attached to the FAE URL
	      [prefix + "mimetype.value.html", "text/html"] // the variable name that will convey the mime type of the passed data
	   ];
	   var prefString;
	   
	   for(var i=0; i<defaults.length; i++) {
	   	  if( !pref.prefHasUserValue(defaults[i][0]) ) {
	   	  	pref.setCharPref(defaults[i][0],defaults[i][1]);
	   	  } // endif
	   } // end for
	   
	},
	
	accessext_createPostPage: function(serializedDocs) {
	   var pref = getAccessextPrefService();
	   var mode = pref.getCharPref("fae.mode.value");
	   var url = pref.getCharPref("fae.url");
	   var report_title = "FAE report from Mozilla Accessibility Extension";
	   var docURL = pref.getCharPref("fae.docURL");
	   var num_docs = serializedDocs.length;  
	   var page = accessext_generatePage("about:blank");
	   var body = page.documentElement.childNodes[1];
	   
	   var form = page.createElement("form");
	   form.setAttribute("enctype", "application/x-www-form-urlencoded");   
	   form.setAttribute("method", "post");
	   form.setAttribute("action", url);   
	   
	   var message = page.createElement("h2");
	   message.appendChild(page.createTextNode("Loading... Please wait."));
	   body.appendChild(message);
	   
	   var formDiv = page.createElement("div");
	   
	   var submitInput = page.createElement("input");
	   submitInput.setAttribute("type", "submit");
	   submitInput.setAttribute("value", "Evaluate");
	   submitInput.setAttribute("style", "visibility: hidden;");
	   formDiv.appendChild(submitInput);
	   
	   var modeInput = page.createElement("input");
	   modeInput.setAttribute("type", "hidden");
	   modeInput.setAttribute("name", "mode");
	   modeInput.setAttribute("value", mode);
	   formDiv.appendChild(modeInput);
	   
	   var docURLInput = page.createElement("input");
	   docURLInput.setAttribute("type", "hidden");
	   docURLInput.setAttribute("name", "url");
	   docURLInput.setAttribute("value", docURL);
	   formDiv.appendChild(docURLInput);
	   
	   var report_titleInput = page.createElement("input");
	   report_titleInput.setAttribute("type", "hidden");
	   report_titleInput.setAttribute("name", "report_title");
	   report_titleInput.setAttribute("value", report_title);
	   formDiv.appendChild(report_titleInput);
	   
	   var num_docsInput = page.createElement("input");
	   num_docsInput.setAttribute("type", "hidden");
	   num_docsInput.setAttribute("name", "num_docs");
	   num_docsInput.setAttribute("value", num_docs);
	   formDiv.appendChild(num_docsInput);
	   
	   for(var i = 0; i < num_docs; i++) {
	      var dataInput = page.createElement("input");
	      dataInput.setAttribute("type", "hidden");
	      dataInput.setAttribute("name", "doc" + (i+1));
	      dataInput.setAttribute("value", encodeURIComponent(serializedDocs[i]));
	      formDiv.appendChild(dataInput);
	   }
	   
	   form.appendChild(formDiv);
	   body.appendChild(form); 
	   
	   submitInput.click(); 
	},
	
	openAndReuseOneTabPerURL: function(url) {
		  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
		                     .getService(Components.interfaces.nsIWindowMediator);
		  var browserEnumerator = wm.getEnumerator("navigator:browser");
	
		  // Check each browser instance for our URL
		  var found = false;
		  while (!found && browserEnumerator.hasMoreElements()) {
		    var browserInstance = browserEnumerator.getNext().getBrowser();
	
		    // Check each tab of this browser instance
		    var numTabs = browserInstance.tabContainer.childNodes.length;
		    for(var index=0; index<numTabs; index++) {
		      var currentBrowser = browserInstance.getBrowserAtIndex(index);
		      if (url == currentBrowser.currentURI.spec) {
	
		        // The URL is already opened. Select this tab.
		        browserInstance.selectedTab = browserInstance.tabContainer.childNodes[index];
	
		        // Focus *this* browser
		        browserInstance.focus();
		        found = true;
		        break;
		      }
		    }
		  }
	
		  // Our URL isn't open. Open it now.
		  if (!found) {
		    var recentWindow = wm.getMostRecentWindow("navigator:browser");
		    if (recentWindow) {
		      // Use an existing browser window
		      recentWindow.delayedOpenTab(url, null, null, null, null);
		    }
		    else {
		      // No browser windows are open, so open a new one.
		      window.open(url);
		    }
	
	/*			if (window.opener == null) {
		      		getBrowser().contentWindow.location = url;
		      		generatedPage = getBrowser.contentWindow;
				} else {
		        	window.opener.getBrowser().contentWindow.location = url;
		      		generatedPage = window.opener.getBrowser().contentWindow;
				} 
	*/		  
		  }
	},
	
	listenForFAE: function() {
		return;
		
		AE.thewindow = window.parent._content;
		AE.mydoc = thewindow.document;
		//fae.cita.uiuc.edu
		//if (mydoc.location == 'http://devserv.dres.uiuc.edu/ita/sfoltz/TestPages/FAEInvokeExtension.html' ) {
		var loc = AE.mydoc.location + ' ';
		if (loc.indexOf('devserv.dres.uiuc.edu') >= 0 ) {
			var node = AE.mydoc.getElementById("FFAccessibilityExtAddChildHere");
			if (node != null) {
				var txtMsg = AE.mydoc.createTextNode('FF Accessibility Extension Dynamically Generated Content')
				node.appendChild(txtMsg);			
			}			
		}
		return;
		
		
	 	try {
		  	var currStd = currStandard();
			var ver = '';
			
			AE.thewindow = window.parent._content;
			AE.mydoc = thewindow.document;
			var node = AE.mydoc.getElementsByTagName("meta");
			for (var i =0; i < node.length && ver == ''; i++) {
				if (node[i].getAttribute("name")) {
					if (node[i].getAttribute("name").toLowerCase() == 'author')	{
						if (node[i].getAttribute("content") == "Nicholas Hoyt; Matthew R. Kramer") { ver = '1.0'}
					}
				}
			} 
			var viaExtention = false;
			var td = AE.mydoc.getElementsByTagName("td");
			for (var i =0; i < td.length && !viaExtention; i++) {
				if (td[i].textContent.indexOf('URL: Unspecified') >= 0 ) {
					viaExtention = true;
				}
			} 
			if (viaExtention && ver != '') {   
				if (currStd != 'icita07') {	alert('Warning: You currently have the beta Rule Set selected, only the FAE rule set will produce results consistent with FAE.');}
				if (ver != '1.1') {	alert("The Firefox Accessibility Extension's FAE rule set is out of date, please update the Firefox Accessibility Extension to avoid inconsistant results.");}
				
				var node = AE.mydoc.getElementsByTagName("h1");
				if (node != null) {
					var txtMsg = AE.mydoc.createTextNode(' Including Dynamically Generated Content')
					node[0].appendChild(txtMsg);			
				}			
			}
			
		} catch (ex) {
			accessext_consoleDump('listenForFAE exception: ', ex);
		}
	},
	
	/** 
	 * Opens a new window and displays the given string in a textarea.
	 * Useful for debugging the XML serialization of a page.
	 * @param str String - string to display
	 * @returns A reference to the new document
	 */
	displayInTextarea: function(str) { 
		try {
			var newpage = window.open().content.document;
		  // var newpage = accessext_generatePage("about:blank");
		   var newbody = newpage.documentElement.childNodes[1];
		   var newp = newpage.createElement("textarea");
		   newp.setAttribute("rows","40");
		   newp.setAttribute("cols","100"); 
		//   alert(str)
		   newp.appendChild(newpage.createTextNode(str));  
		   newbody.appendChild(newp);
		   return newpage;
		} catch (ex) {
			accessext_consoleDump('displayInTextarea exception: ' + ex);
		} 
	 },

	accessext_faeConfigReset: function() {
	   var faeUnmergedNode = document.getElementById("accessext_faeUnmerged");
	   var faeIframes = document.getElementById("accessext_faeIncludeIframes");
	   
	   faeUnmergedNode.click();
	   faeIframes.setAttribute("checked", "false");
	},
	
	accessext_faeConfigSave: function() {
		try {
		   var faeIframes = document.getElementById("accessext_faeIncludeIframes").getAttribute("checked");
		   var faeMergedNode = document.getElementById("accessext_faeMerged").getAttribute("selected");
		  	
		   var iframesChecked = faeIframes === "true" ? true : false;
		   var mergeSelected = faeMergedNode === "true" ? true : false;
		
		   var prefService = getAccessextPrefService();
		   
		   prefService.setBoolPref("fae.mergeFrames", mergeSelected);
		   prefService.setBoolPref("fae.includeIframes", iframesChecked);
		   return true;
		} catch (ex) {
			accessext_consoleDump('accessext_faeConfigSave exception: ', ex);
		}
	},
	
	accessext_faeConfigInitial: function() {
	   var faeIframes = document.getElementById("accessext_faeIncludeIframes");
	   if (faeIframes == null) return; //not in faeConfig.xul so skip this function
	   
	   var faeMergedNode = document.getElementById("accessext_faeMerged");
	   var faeUnmergedNode = document.getElementById("accessext_faeUnmerged");
	   var faeURLNode = document.getElementById("accessext_faeURL");
	   
	   var pref = getAccessextPrefService();
	   
	   if(pref.getBoolPref("fae.includeIframes")){
	      faeIframes.setAttribute("checked", "true");
	   } else {
	      faeIframes.setAttribute("checked", "false");
	   }
	   
	   if(pref.getBoolPref("fae.mergeFrames")) {
	      faeMergedNode.click();
	   } else {
	      faeUnmergedNode.click();
	   }
	}
});
AccessibilityExtension.LIB.accessext_faeConfigInitial();	
}});